from cibynet.model import meta


def GetOneObject(ObjectClass, **kwargs):
  """Given a set of parameters and a class, return ONE object, or None.
  If more than one object is available, return None.
  
  Arguments:
    - ObjectClass (type): the class of the object you want to fetch.
    - kwargs: keys: attributes you want to filter on.
              values: values of the attributes.
  """
  obj_q = meta.Session.query(ObjectClass)
  try:
    for k, v in kwargs.iteritems():
      obj_q = obj_q.filter(getattr(ObjectClass, k) == v)
    obj = obj_q.one()
  except Exception:
    return None
  return obj


def GetAllObjects(ObjectClass, **kwargs):
  """Given a set of parameters and a class, return ALL corresponding objects, 
  or [].
  
  Arguments:
    - ObjectClass (type): the class of the object you want to fetch.
    - kwargs: keys: attributes you want to filter on.
              values: values of the attributes.
  """
  obj_q = meta.Session.query(ObjectClass)
  for k, v in kwargs.iteritems():
    obj_q = obj_q.filter(getattr(ObjectClass, k) == v)
  return obj_q.all()


def GetAllIdsObject(ObjectClass, **kwargs):
  """Given a set of parameters and a class, return ALL corresponding objects ids, 
  or [].
  
  Arguments:
    - ObjectClass (type): the class of the object you want to fetch.
    - kwargs: keys: attributes you want to filter on.
              values: values of the attributes.
  """
  q = meta.Session.query(ObjectClass.id)
  for k, v in kwargs.iteritems():
    q = q.filter(getattr(ObjectClass, k) == v)
  return [r[0] for r in q.all()]


class ObjectHavingIp(object):
  """This class contains getter/setter/deleter for the attribute _ip.
  Any class heritating from this one will enforce a verification on the ip 
  (available or not)
  """
  
  def _set_ip(self, ip):
    """Attribute a(n new) ip (IP object) to the object.
    
    Arguments:
      - ip: string.
    """
    assert ip.available, ip
    ip.available = False
    if getattr(self, '_ip', None):
      self._ip.available = True
    self._ip = ip
    
  def _get_ip(self):
    """Returns the ip (IP object) of the object.
    """
    return self._ip
  
  def _del_ip(self):
    """Untie the ip and the object.
    """
    self._ip.available = True
    del self._ip
    
  ip = property(_get_ip, _set_ip, _del_ip)
  

class UpdatableObject(object):
  """This class provides the update(**kwargs) method which take any (k, v)
  and put v into UpdatableObject.k .
  """
  
  def update(self, new_values):
    """Returns None. Use the key/values from new_values dict to set
    attributes on the object.
    
    Arguments:
      - new_values: dict(k, v) containing the new values v for the attributes k.
    """
    for k, v in new_values.iteritems():
        self.__setattr__(k, v)


def UnicodeLowerCaseTitleProperty(hidden_attr):
  """Return property to get/set string or None on a given attribute.
      - setter lowers the string and converts it to unicode if necessary.
      - getter titles the string.
    
  Arguments:
    - hidden_attr: string, name of the attribute that will be used 
      by the property.
  """
  def setter(obj, value):
    if value is not None: 
      value = unicode(value.lower())
    setattr(obj, hidden_attr, value)
  def getter(obj):
    value = getattr(obj, hidden_attr)
    if value: 
      value = value.title()
    return value
  return property(getter, setter)


def UnicodeLowerCaseProperty(hidden_attr):
  """Return property to get/set string or None on a given attribute.
      - setter lowers the string and converts it to unicode if necessary.
      - getter just returns the string.
    
  Arguments:
    - hidden_attr: string, name of the attribute that will be used 
      by the property.
  """
  def setter(obj, value):
    if value is not None: 
      value = unicode(value.lower())
    setattr(obj, hidden_attr, value)
  def getter(obj):
    value = getattr(obj, hidden_attr)
    return value
  return property(getter, setter)

def UnicodeProperty(hidden_attr):
  """Return property to get/set string or None on a given attribute.
      - setter converts the string to unicode if necessary.
      
  Arguments:
    - hidden_attr: string, name of the attribute that will be used 
      by the property.
  """
  def setter(obj, value):
    if value is not None: 
      value = unicode(value)
    setattr(obj, hidden_attr, value)
  def getter(obj):
    return getattr(obj, hidden_attr)
  return property(getter, setter)
  